//放音程序，演示alsa library的使用
#include <stdio.h>          //fprintf
#include <alsa/asoundlib.h> //alsa

int main(int argc, char** argv)
{
    //声音设备句柄
    snd_pcm_t *dev = NULL;
    //打开音频设备
    int error = snd_pcm_open(&dev, "sysdefault", SND_PCM_STREAM_PLAYBACK, 0);
    if (error != 0)
    {
        fprintf(stderr, "snd_pcm_open() failed: %s\n", snd_strerror(error));
        return EXIT_FAILURE;
    }

    //设置硬件参数
    snd_pcm_hw_params_t *hw_params;
    //分配硬件参数内存
    snd_pcm_hw_params_alloca(&hw_params);
    //初始化硬件参数，使用默认值
    snd_pcm_hw_params_any(dev, hw_params);

    //多声道交错存储，读写方式
    snd_pcm_hw_params_set_access(dev, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED);

    //设置采样格式：有符号16位整数，小端字节序
    snd_pcm_hw_params_set_format(dev, hw_params, SND_PCM_FORMAT_S16_LE);

    //设置采样率：16000Hz
    snd_pcm_hw_params_set_rate(dev, hw_params, 16000, 0);

    //设置声道数：单声道
    snd_pcm_hw_params_set_channels(dev, hw_params, 1);

    //根据硬件参数配置声卡设备
    error = snd_pcm_hw_params(dev, hw_params);
    if (error != 0)
    {
        fprintf(stderr, "snd_pcm_hw_params() failed: %s\n", snd_strerror(error));
        return EXIT_FAILURE;
    }

    FILE* fp = NULL;
    if (argc < 2)
    {
        fp = stdin;
    }
    else {
        fp = fopen(argv[1], "r");
    }
    
    if (fp == NULL)
    {
        perror("fopen() failed");
        return EXIT_FAILURE;
    }

    //获取声卡一次传输数据的大小
    unsigned long period = 0;
    int dir = 0;
    snd_pcm_hw_params_get_period_size(hw_params, &period, &dir);

    //buf大小是period整数倍
    char* buf = malloc(period*2);

    //开始放音
    snd_pcm_prepare(dev);

    snd_pcm_sframes_t frames;
    while ((frames = fread(buf, 2, period, fp)))
    {
        snd_pcm_writei(dev, buf, frames);
    }

    //停止放音
    snd_pcm_drain(dev);
    //关闭声音设备
    snd_pcm_close(dev);
    fclose(fp);
    free(buf);

    return 0;
}
